package algoritmo2;

import algoritmo.*;
import java.awt.Color;
import java.awt.Font;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;



import org.jfree.data.category.DefaultCategoryDataset;
import org.math.plot.Plot2DPanel;
import org.math.plot.plotObjects.BaseLabel;

import algoritmo2.cruces.Cruce;
import algoritmo2.cruces.Cruce1;
import algoritmo2.mutacion.Mutacion;
import algoritmo2.mutacion.MutacionArbol;
import algoritmo2.mutacion.MutacionFuncional;
import algoritmo2.mutacion.MutacionPropia;
import algoritmo2.mutacion.MutacionPropia2;
import algoritmo2.mutacion.MutacionTerminal;
import gui2.InformacionBean;
import gui2.ProgresoJFrame;
import gui2.ResultadosJFrame;

public class Controlador extends Thread {

    // Tipo de cruce y de mutaci�n
    private Cruce claseCruce;
    private Mutacion claseMutacion;
    // Array de elitistas
    Individuo[] elite;
    private InformacionBean informacion = null;
    // variable para la grafica
    DefaultCategoryDataset dataset = new DefaultCategoryDataset();
    // Atributos con los datos que hay que graficar
    private double[] generaciones;
    private double[] mejoresIndividuos;
    private double[] medias;
    private ResultadosJFrame result;
    private ProgresoJFrame progreso;

    public Controlador(InformacionBean informacion, ResultadosJFrame result,
            ProgresoJFrame progreso) {
        this.informacion = informacion;
        this.result = result;
        this.progreso = progreso;

    }

    @Override
    public void run() {
        ejecutarAlgoritmo();


    }

    public void ejecutarAlgoritmo() {
        progreso.setVisible(true);
        // Inicializamos los atributos para la discusi�n de resultados
        generaciones = new double[informacion.getMaxGeneraciones()];
        mejoresIndividuos = new double[informacion.getMaxGeneraciones()];
        medias = new double[informacion.getMaxGeneraciones()];

        switch (informacion.getSeleccionMutacion()) {
            case 0:
                claseMutacion = new MutacionFuncional();
                break;
            case 1:
                claseMutacion = new MutacionTerminal();
                break;
            case 2:
                claseMutacion = new MutacionArbol();
                break;
            case 3:
                claseMutacion = new MutacionPropia();
                break;
            case 4:
                claseMutacion = new MutacionPropia2();
                break;

        }

        switch (informacion.getSeleccionCruce()) {
            case 0:
                claseCruce = new Cruce1();
                break;

        }

        AGenetico AG = new AGenetico(informacion.getTamanioPoblacion(),
                informacion.getMaxGeneraciones(), informacion.getProbCruce(),
                informacion.getProbMutacion(), informacion.getSeleccionReproduccion(), claseMutacion, claseCruce, informacion.getHmax(), informacion.isCompleta(),
                informacion.getCjtoFun(), informacion.getCjtoTer(), informacion.getRate());

        AG.inicializa();
        AG.evaluarPoblacion(informacion.isEscalado(), informacion.getValorEscalado());
        double mejorGeneraciones = Integer.MIN_VALUE;
        while (!AG.terminado() && AG.getElMejor().evalua(informacion.getRate()) != 64) {

            AG.incrementarGeneracion();
            progreso.actualizarProgress(informacion, AG.getNumGeneracion(), AG.getElMejor());

            // Antes de realizar operaciones gen�ticas, separamos a los mejores
            elite = AG.separarElite(informacion.getPorcentajeElitismo());

            // Selecci�n
            AG.seleccion(informacion.isElitismo(), informacion.getPorcentajeElitismo());
            // Reproducci�n
            AG.reproduccion();
            // Mutaci�n
            AG.mutacion();

            // Incluimos nuevamente a la �lite
            AG.incluyeElite(elite);

            // Volvemos a evaluar la poblaci�n
            AG.evaluarPoblacion(informacion.isEscalado(), informacion.getValorEscalado());

            // Actualizamos acordemente las generaciones, mejores y medias
            generaciones[AG.getNumGeneracion() - 1] = AG.getNumGeneracion();
            if (AG.getElMejor().getAptitud() > mejorGeneraciones) {
                mejorGeneraciones = AG.getElMejor().evalua(1);
            }
            mejoresIndividuos[AG.getNumGeneracion() - 1] = mejorGeneraciones;
            medias[AG.getNumGeneracion() - 1] = obtenerMedia(AG);
            /*pintaIndividuos(AG);
            try {
                System.in.read();
                // // obtenemos el mejro para crear la grafica
                // actualizarGraficaElMejor(AG, AG.getNumGeneracion());
                // actualizarGraficaMedia(AG, AG.getNumGeneracion());
            } catch (IOException ex) {
                Logger.getLogger(Controlador.class.getName()).log(Level.SEVERE, null, ex);
            }*/
            // // obtenemos el mejro para crear la grafica
            // actualizarGraficaElMejor(AG, AG.getNumGeneracion());
            // actualizarGraficaMedia(AG, AG.getNumGeneracion());
        }

        if(AG.getElMejor().evalua(informacion.getRate()) == 64){
            double media = medias[AG.getNumGeneracion() - 1];
            while(!AG.terminado()){
                AG.incrementarGeneracion();
                 mejoresIndividuos[AG.getNumGeneracion() - 1] = AG.getElMejor().evalua(1);
                 medias[AG.getNumGeneracion() - 1] = media;
                 generaciones[AG.getNumGeneracion() - 1] = AG.getNumGeneracion();
            }
            
        }
        Individuo elmejor = AG.getElMejor();
        StringBuilder trace = new StringBuilder();

        trace.append("\nEl mejor resultado es   " + elmejor.evalua(1));
        trace.append("\nEl árbol resultante es: " + elmejor.getArbol().toString(""));

        result.insertText(trace.toString());
        String text = "Tamaño población: " + informacion.getTamanioPoblacion() + ", Num generaciones: " + informacion.getMaxGeneraciones() + ", prob cruce: " + informacion.getProbCruce() + ", prob mutación: " + informacion.getProbMutacion();
        mostrarGrafica2D(generaciones, mejoresIndividuos, medias, text);
        progreso.setVisible(false);
        result.setVisible(true);
    }

   

    // Esta funci�n es una adaptaci�n de lo que hizo Ra�l para las otras
    // gr�ficas
    private double obtenerMedia(AGenetico AG) {
        Individuo[] pob = AG.getPob();
        double media = 0;
        for (int i = 0; i < pob.length; i++) {
            media += pob[i].evalua(1);
        }
        media = media / pob.length;
        return media;
    }

    private void mostrarGrafica2D(double[] generaciones,
            double[] mejoresIndividuos, double[] medias, String text) {
        // El eje x ser�n las generaciones, el eje y ser�n los mejores
        // individuos y la media de la poblaci�n

        // Creamos el Plot2D
        Plot2DPanel plot = new Plot2DPanel();

        BaseLabel title = new BaseLabel(text, Color.BLACK, 0.5, 1.1);
        title.setFont(new Font("Arial", Font.BOLD, 15));
        plot.addPlotable(title);
        plot.addLegend("SOUTH");

        plot.setAxisLabels("N�m. Generaciones", "Valor");
        // Ahora a�adimos las gr�ficas
        plot.addLinePlot("Gr�fica de generaciones/mejores individuos",
                generaciones, mejoresIndividuos);
        plot.addLinePlot("Gr�fica de generaciones/medias poblaci�n",
                generaciones, medias);
        plot.getAxis(0).setLabelPosition(0.5, -0.15);
        plot.getAxis(1).setLabelPosition(-0.15, 0.5);
        // Las mostramos
        JFrame frame = new JFrame("Gr�ficas de resultados");
        frame.setSize(600, 600);
        frame.setContentPane(plot);
        frame.setVisible(true);
    }
}
